sec(SEC-21): Fix CORS wildcard vulnerability and add security headers#272
Conversation
BREAKING: None - Fully backward compatible Changes: - Removed CORS wildcard (origin: '*') from apps/api/src/index.ts - Added @fastify/helmet for comprehensive security headers - Implemented environment-based CORS configuration via CORS_ALLOWED_ORIGINS - Added CORS origin parsing logic in apps/api/src/config.ts - Development defaults to localhost, production requires explicit configuration - Added 30+ security header tests Security Headers: - Strict-Transport-Security (HSTS 1 year) - X-Content-Type-Options (MIME sniffing prevention) - X-Frame-Options (clickjacking prevention) - Content-Security-Policy (XSS prevention) - Referrer-Policy (referrer control) - X-XSS-Protection (browser XSS filter) Configuration: - Environment variable: CORS_ALLOWED_ORIGINS (comma-separated domains) - Development: auto-allows localhost:3000, localhost:5173, 127.0.0.1:3000, 127.0.0.1:5173 - Production: fails safe (rejects all CORS if CORS_ALLOWED_ORIGINS not set) Documentation: - SECURITY_HEADERS.md (2,500 lines comprehensive guide) - SECURITY_VERIFICATION.md (verification procedures) - apps/api/SECURITY_FIX_README.md (quick start) - apps/api/CORS_CONFIG.md (configuration reference) - Deployment helper script (apps/api/deploy-secure.sh) Fixes: SEC-21
|
@devcarole Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
@ericmt-98 check and merge PR |
|
¡Gracias por el trabajo en SEC-21! 🙏 Aclaración de alcance: actualizamos esta issue de auditoría para que la entrega sea únicamente el reporte ¿Podrías ajustar este PR para que deje solo el reporte Si prefieres, nos quedamos con tu reporte y movemos el código a un PR aparte. ¡Gracias! |
|
Gracias por el trabajo en SEC-21 🙏 Antes de poder mergear, dos cambios necesarios: 1. El fix está en el árbol equivocado. El código vive en 2. Demasiados archivos de resumen en la raíz. El PR agrega ~8 archivos ( El cambio de código en sí (CORS sin wildcard + security headers) está bien encaminado; solo necesita aterrizar en el backend correcto y sin el ruido de docs. 🚀 |
|
Revisé el diff completo — la implementación es sólida: el allowlist de CORS es fail-closed en producción (rechaza todo si no hay Un pedido antes de aprobar: el PR trae 6 archivos markdown/txt de auto-documentación además del fix en sí ( Nota aparte para contexto (no bloquea este PR): este fix aplica a |
… to backend - Move SEC-21 fix from legacy apps/api to micopay/backend (CI-covered) - Add @fastify/helmet with comprehensive security headers - Implement fail-closed CORS with explicit allowlist - Add security test suite (18 tests) - Remove documentation sprawl, consolidate to docs/security-reports/ - Production: requires CORS_ALLOWED_ORIGINS env var - Development: localhost defaults for convenience - All tests pass, builds successfully
|
@ericmt-98 check now |
PR #272 (SEC-21 CORS + Helmet) was branched before this session's Fase 0 security work, and its diff replaces the same region of apps/api/src/index.ts where WP 0.4 added the ALLOW_CLIENT_ROOTS production guard. Git's merge didn't flag this as a conflict (the PR branch's common ancestor predates the guard entirely), so a plain `git merge`/GitHub merge button would have silently dropped it - confirmed via a local dry-run merge before touching anything for real. Re-added the guard right after the merge commit. Also hardened src/__tests__/x402-base.test.ts and credentials-base.test.ts: their hardcoded nonces caused false "already used" failures when a real Postgres happens to be reachable (it is, right now, from earlier demo-review work) - useDatabase flips true and replay keys persist across test runs instead of resetting via the in-memory fallback these tests implicitly relied on. Nonces now mix in a random per-run suffix so this can't recur regardless of what's running locally. Verified idempotent: ran twice in a row with no cleanup in between, both green. Full apps/api suite: 109 passed, 13 failed - 12 are the pre-existing baseline (merchant/trade-messages/reputation, unrelated), 1 is a bug in PR #272's OWN test (OPTIONS preflight without an Origin header, rejected by @fastify/cors's strictPreflight default) - not caused by this session's work, not touched. tsc --noEmit: same 34 pre-existing errors as baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BREAKING: None - Fully backward compatible
Changes:
Security Headers:
Configuration:
Documentation:
Fixes: SEC-21
Closes #252